from collections import Iterable
from collections import Iterator

# 如果列表元素可以按照某种算法推算出来，就不必创建完整的list，从而节省大量的空间。
# 在Python中，这种一边循环一边计算的机制，称为生成器：generator。
g = (x * x for x in range(1, 11))

print(g)  # 生成一个generator

# generator也是一个迭代对象
print([x for x in g])  # 输出[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 计算斐波那契数列的普通方法


def fib(max):
    a, b, n = 1, 1, 0
    while n < max:
        print(a)
        a, b = b, a + b
        n = n + 1
    print('done')


fib(6)  # 输出1 1 2 3 5 8

'''
简单地讲，yield 的作用就是把一个函数变成一个 generator。
带有 yield 的函数不再是一个普通函数，Python 解释器会将其视为一个 generator。
调用 fab(5) 不会执行 fab 函数，而是返回一个 iterable 对象！
在 for 循环执行时，每次循环都会执行 fab 函数内部的代码，
执行到 yield b 时，fab 函数就返回一个迭代值，
下次迭代时，代码从 yield b 的下一条语句继续执行，而函数的本地变量看起来和上次中断执行前是完全一样的，
于是函数继续执行，直到再次遇到 yield。
'''


def fib_new(max):
    a, b, n = 1, 1, 0
    while n < max:
        yield a
        a, b = b, a + b
        n = n + 1
    print('done')


for i in fib_new(6):
    print(i)  # 生成器是可以迭代的

# 所谓的迭代器，不仅可以使用for循环(iterable)，还可以使用next函数(iterator)
b = fib_new(6)
i = 0
while i < 6:
    print(next(b))  # 使用next()函数输出1 1 2 3 5 8
    i = i + 1

# 能使用for和next函数就叫做迭代器，用isinstance()函数判断是不是迭代器
print(isinstance(b, Iterable))  # 可迭代
print(isinstance(b, Iterator))  # 是迭代器

print(isinstance([0], Iterable))  # 可迭代
print(isinstance([0], Iterator))  # 不是迭代器，只能用for循环不能用next
